/*
 * Transport.h
 *
 *  Created on: Jun 7, 2011
 *      Author: Mario Hock
 */

#ifndef TRANSPORT_H_
#define TRANSPORT_H_

#include "ariba/ariba.h"
#include "Userdatabase.h"
#include "messages/TransportMessage.h"
#include "messages/ChatMessage.h"
#include "ARQQueue.h"

#include <string>
#include <vector>
#include "interfaces/Useroutputinterface.h"
#include "interfaces/MessageHandlerInterface.h"
#include "interfaces/DhtInterface.h"
#include "interfaces/ConnStatInterface.h"

using namespace std;

class Transport :
  public ariba::NodeListener,
  public ariba::CommunicationListener
{
public:
      typedef enum
      {
          CONNECT = 0,
          CONFIRM_CONNECTION = 1,
          DISCONNECT = 2,
          CONFIRM_DISCONNECT = 3,
          DENY_CONNECTION = 4,
          AUTHENTICATION_ERROR = 5
      } CONNECT_SUBTYPE;


  /** constructor / destructor **/
  Transport();
  Transport(ariba::AribaModule* ariba, ariba::Node* node, Userdatabase* users);
  virtual
  ~Transport();


  bool send_to(const ariba::DataMessage& msg, TransportMessage::MESSAGE_TYPE type, uint8_t subtype, UserPtr user);
//  void send_direct(const ariba::DataMessage& msg, TransportMessage::MESSAGE_TYPE type, uint8_t subtype, UserPtr user);
  void send_eventually(const ariba::DataMessage& msg, TransportMessage::MESSAGE_TYPE type, uint8_t subtype, UserPtr user, string receipt);

  void establish_connection(UserPtr user);
  void close_connection(UserPtr user);
  void close_all_connections();

  void register_message_handler(MessageHandlerInterface* handler, TransportMessage::MESSAGE_TYPE type);
  void register_conn_stat_notification(ConnStatInterface* handler);

  string overlay_info();
  
  void save_arq_queue(const path& message_dir);
  void load_arq_queue(const path& message_dir);

protected:
  /** CommunicationListener interface **/
  virtual bool onLinkRequest(const ariba::NodeID& remote);
  virtual void onMessage(const ariba::DataMessage& msg, const ariba::NodeID& remote,
          const ariba::LinkID& lnk = ariba::LinkID::UNSPECIFIED);
  virtual void onLinkUp(const ariba::LinkID& lnk, const ariba::NodeID& lscrew);
  virtual void onLinkDown(const ariba::LinkID& lnk, const ariba::NodeID& lscrew);
  virtual void onLinkChanged(const ariba::LinkID& lnk, const ariba::NodeID& lscrew);
  virtual void onLinkFail(const ariba::LinkID& lnk, const ariba::NodeID& remote);

  /** NodeListener Interface**/
  virtual void onJoinCompleted( const ariba::SpoVNetID& id );
  virtual void onJoinFailed( const ariba::SpoVNetID& id );
  virtual void onLeaveCompleted( const ariba::SpoVNetID& id );
  virtual void onLeaveFailed( const ariba::SpoVNetID& id );


private:
  void _send_to(const ariba::DataMessage& msg, TransportMessage::MESSAGE_TYPE type, uint8_t subtype, UserPtr user);
  void handleMessage(const ariba::DataMessage& msg, const ariba::NodeID& sender_id, const ariba::LinkID on_link);
  void handle_connect(TransportMessage* msg, TransportMessage::MESSAGE_TYPE type, uint8_t subtype, UserPtr user);
  void close_connection_raw(UserPtr user);
  void notify_conn_stat(UserPtr user, bool connected);
  
  void arq_on_connection_established(UserPtr user);

public:  // FIXME private
  ariba::AribaModule* ariba;
  ariba::Node* node;
  Useroutputinterface* ui;
  Userdatabase* users;
  ariba::ServiceID serviceID;
  bool joinFailedFlag;

//  vector<MessageHandlerInterface*> messageHandler;
  MessageHandlerInterface* messageHandler[10]; //TODO nicht 10!
  DhtInterface* dht_handler; //TODO nur einer?
  vector<ConnStatInterface*> conn_stat_notification;
  
  ARQ_Queue arq_queue;
};

#endif /* TRANSPORT_H_ */
